package masterjava.common.client.gwt.dao;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import masterjava.common.shared.FetchContext;
import masterjava.common.shared.entity.GenericEntity;
import masterjava.common.shared.rpc.DaoRemoteService;
import masterjava.common.shared.rpc.DaoRemoteServiceAsync;

import java.io.Serializable;
import java.util.List;

/**
 * User: Grigory Kislin
 * Date: 27/06/11
 * <p/>
 * Typed DAO at client side
 * <p/>
 * Make Instances as singletons (client side has no DI)
 */
public class ClientDao<T extends GenericEntity<ID>, ID extends Serializable> {
    private static final DaoRemoteServiceAsync DAO_SERVICE = GWT.create(DaoRemoteService.class);

    protected final String persistentClass;

    // Context only for current request
    protected FetchContext ctx;

    public ClientDao(Class<T> persistentClass) {
        this.persistentClass = persistentClass.getName();
    }

    public void get(ID id, AsyncCallback<T> callback) {
        GWT.log("get " + persistentClass + ":" + id);
        DAO_SERVICE.get(persistentClass, id, callback);
    }

    public void saveOrUpdate(T entity, AsyncCallback<ID> callback) {
        GWT.log("saveOrUpdate of " + entity.toString());
        DAO_SERVICE.saveOrUpdate(entity, callback);
    }

    public void getAll(AsyncCallback<List<T>> callback) {
        GWT.log("getAll " + persistentClass);
        AsyncCallback rawCallback = callback;
        DAO_SERVICE.loadAll(persistentClass, ctx, rawCallback);
        ctx = null;
    }

    public void delete(ID id, AsyncCallback<Void> callback) {
        GWT.log("delete " + persistentClass + ":" + id);
        DAO_SERVICE.delete(persistentClass, id, callback);
    }

    public void findByNamedQueryAndNamedParam(String queryName, String[] paramNames, Serializable[] values, AsyncCallback<List<T>> callback) {
        GWT.log("findByNamedQueryAndNamedParam " + persistentClass + "(queryName:" + queryName + ")");
        AsyncCallback rawCallback = callback;
        DAO_SERVICE.findByNamedQueryAndNamedParam(queryName, paramNames, values, ctx, rawCallback);
        ctx = null;
    }

    public void findUnique(String queryName, String[] paramNames, Serializable[] values, AsyncCallback<T> callback) {
        GWT.log("findUnique " + persistentClass + "(queryName:" + queryName + ")");
        DAO_SERVICE.findUnique(queryName, paramNames, values, callback);
        ctx = null;
    }


    public void findByNamedQueryAndNamedParam(String queryName, String paramName, Serializable value, AsyncCallback<List<T>> callback) {
        findByNamedQueryAndNamedParam(queryName, new String[]{paramName}, new Serializable[]{value}, callback);
    }

    public void findUnique(String queryName, String paramName, Serializable value, AsyncCallback<T> callback) {
        findUnique(queryName, new String[]{paramName}, new Serializable[]{value}, callback);
    }

    public ClientDao<T, ID> setCacheQueries(boolean cacheQueries) {
        getContext().setCacheQueries(cacheQueries);
        return this;
    }

    public ClientDao<T, ID> setFirstResult(int firstResult) {
        getContext().setFirstResult(firstResult);
        return this;
    }

    public ClientDao<T, ID> setMaxResults(int maxResults) {
        getContext().setMaxResults(maxResults);
        return this;
    }

    protected FetchContext getContext() {
        if (ctx == null) {
            ctx = new FetchContext();
        }
        return ctx;
    }
}
